import { _decorator, Component, TiledMap, instantiate, Node, Prefab, TiledTile } from 'cc';
import { PlayerType, UnitType, TildeType, EntityType, getClientTildeType, CommandType, BuildingType } from '../../../battle/Enums';
import { getUnitConfig, getBuildingConfig, ResourceConfig, MapSettings, MapConfigs, SplashDamageRatio } from '../../../battle/Const';
import { CommandParam, SwapCommandParam, BuildCommandParam, InitCommandParam } from '../../../battle/Model';
import { TiledObject } from './TiledObject';
import { InfoTip } from '../ui/InfoTip';
import { ToggleType, UIManager } from '../ui/UIManager';
import { TiledObjInitConfig } from './TiledObjectData';
import { MessageManager, MessageType } from '../message';
import { LOG } from '../../../ConsoleLogCtrl';

const { ccclass, property } = _decorator;

/**
 * 地图渲染器
 * 负责渲染战斗地图、单位和建筑
 */
@ccclass('MapRenderer')
export class MapRenderer extends Component {
    @property(TiledMap)
    tiledMap: TiledMap = null!;

    @property(InfoTip)
    public tipinfo: InfoTip;

    @property(Prefab)
    public tiledPrefab: Prefab = null!;

    @property(UIManager)
    public uiManager: UIManager = null!;

    @property(Node)
    public prefabs: Node = null!;

    private unitTileSize: number = 24;
    private buildingTileSize: number = 24;
    private tiledTileSize: number = 16;
    private mapData: number[][] = null;
    private mapWidth: number = 0;
    private mapHeight: number = 0;

    // 单位节点映射表，用于快速查找单位节点
    private unitNodes: Map<number, Node> = new Map();
    // 建筑节点映射表，用于快速查找建筑节点
    private buildingNodes: Map<number, Node> = new Map();
    // 地形节点映射表，用于快速查找地形节点
    private terrainNodes: Map<string, Node> = new Map();

    // 被删除的节点存储列表
    private removeUnitNodes: Node[] = [];
    private removeBuildingNodes: Node[] = [];
    private removeTerrainNodes: Node[] = [];
    private message: MessageManager = null;
    private isPause: boolean = false;

    protected onLoad(): void {
       this.initMessage();
    }

    /**
     * 初始化消息订阅
     */
    private initMessage() {
        this.message = MessageManager.getInstance();
        this.message.subscribe(MessageType.GAME_RESET, this.onGameResetCallback, this)
        this.message.subscribe(MessageType.GAME_RESUME, this.onGameResumeCallback, this)
        this.message.subscribe(MessageType.GAME_PAUSE, this.onGamePauseCallback, this)
    }

    /**
     * 游戏重置回调
     * @param message 消息数据
     */
    private onGameResetCallback(message: any) {
        if(this.removeUnitNodes){
            this.removeUnitNodes.forEach(node => {
                node.destroy();
            });
        }
        if(this.removeBuildingNodes){
            this.removeBuildingNodes.forEach(node => {
                node.destroy();
            });
        }
        if(this.removeTerrainNodes){
            this.removeTerrainNodes.forEach(node => {
                node.destroy();
            });
        }
    }

    /**
     * 游戏恢复回调
     * @param message 消息数据
     */
    private onGameResumeCallback(message: any) {
        //TODO 游戏恢复要做的操作
    }

    /**
     * 游戏暂停回调
     * @param message 消息数据
     */
    private onGamePauseCallback(message: any) {
        //TODO 保存被移除的节点
        this.isPause = true;
    }

    /**
     * 清除消息订阅
     */
    private clearMessage() {
        this.message.unsubscribe(MessageType.GAME_RESET);
    }

    /**
     * 渲染地图
     * @param data 初始化命令数据
     */
    public renderMap(data: CommandParam<CommandType.init>, isRender: boolean = true) {
        const initParam = data.param as InitCommandParam;
        this.mapData = MapConfigs[initParam.map];
        this.initializeLayers();
        this.redrawMap();
    }

    /**
     * 重新绘制整个地图
     */
    public redrawMap() {
        if (!this.mapData) {
            LOG.error('MapRenderer: 地图数据为空，无法渲染');
            return;
        }
        const height = this.mapData.length;
        const width = this.mapData[0].length;
        LOG.log(`MapRenderer: 开始渲染地图，尺寸: ${width}x${height}`);

        if (!this.tiledMap) {
            LOG.error('MapRenderer: TiledMap组件未找到，无法渲染地形');
            return;
        }

        // 获取对象层
        let objectGroup = this.tiledMap.getObjectGroup('object');
        if (!objectGroup) {
            LOG.error('MapRenderer: 未找到对象层: object');
            return;
        }

        // 遍历地图数据，创建对应的地形对象
        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                const tileType = this.mapData[y][x] as TildeType;
                if (tileType !== TildeType.flat) {
                    this.createTerrainObject(x, y, tileType, objectGroup);
                }
            }
        }

        LOG.log('MapRenderer: 地图渲染完成');
    }

    /**
     * 创建地形对象节点
     * @param x X坐标
     * @param y Y坐标
     * @param terrainType 地形类型
     * @param objectGroup 对象层
     */
    public createTerrainObject(x: number, y: number, terrainType: TildeType, objectGroup: any): void {
        // 生成唯一的地形节点ID
        const terrainId = `terrain_${x}_${y}`;

        // 检查地形节点是否已存在
        if (this.terrainNodes.has(terrainId)) {
            LOG.warn(`MapRenderer: 地形节点已存在: ${terrainId}`);
            return;
        }

        // 创建TiledObject数据
        let config: TiledObjInitConfig = {
            id: 0, // 地形对象不需要唯一ID
            playerType: PlayerType.ADMIN,
            entityType: EntityType.terrain,
            uType: terrainType,
            position: { x: x, y: y },
            name: `terrain_${terrainType}_${x}_${y}`,
            clientTildeType: getClientTildeType(terrainType, EntityType.terrain),
        };

        // 优先从被删除的地形节点列表中获取节点进行重用
        let terrainNode: Node;
        if (this.removeTerrainNodes.length > 0) {
            // 从列表中取出一个节点进行重用
            terrainNode = this.removeTerrainNodes.pop()!;
            terrainNode.name = terrainId;
            // 从prefabs节点下移除
            if (terrainNode.parent === this.prefabs) {
                this.prefabs.removeChild(terrainNode);
            }
            //LOG.log(`MapRenderer: 重用地形节点: ${terrainId}`);
        } else {
            // 列表为空时创建新节点
            terrainNode = instantiate(this.tiledPrefab);
            terrainNode.name = terrainId;
            terrainNode.active = false;
            //LOG.log(`MapRenderer: 创建新地形节点: ${terrainId}`);
        }
        let tiledObject = terrainNode.getComponent(TiledObject);
        tiledObject.init(config);

        // 创建渲染节点
        tiledObject.createRenderNode(this.tiledTileSize, PlayerType.ADMIN);

        // 将节点添加到对象层
        objectGroup.node.addChild(terrainNode);
        terrainNode.active = true;

        // 保存到映射表
        this.terrainNodes.set(terrainId, terrainNode);
    }

    /**
     * 初始化渲染器
     * @param tiledMap TiledMap组件
     */
    public initialize(tiledMap: TiledMap): void {
        this.tiledMap = tiledMap;
        this.initializeLayers();
    }

    /**
     * 初始化图层
     */
    public initializeLayers(): void {
        if (!this.tiledMap) {
            this.tiledMap = this.getComponent(TiledMap);
        }
        // 获取地图尺寸
        const mapSize = this.tiledMap.getMapSize();
        this.mapWidth = mapSize.width;
        this.mapHeight = mapSize.height;
    }

    /**
     * 检查位置是否有效
     * @param x X坐标
     * @param y Y坐标
     * @returns 是否有效
     */
    public isValidPosition(x: number, y: number): boolean {
        return x >= 0 && x < this.mapWidth && y >= 0 && y < this.mapHeight;
    }

    /**
     * 获取地图尺寸
     * @returns 地图尺寸
     */
    public getMapSize(): { width: number; height: number } {
        return {
            width: this.mapWidth,
            height: this.mapHeight,
        };
    }

    // ==================== 单位渲染方法 ====================

    /**
     * 创建单位显示节点
     * @param unit 单位数据
     * @param playerType 玩家类型
     */
    public createUnit(
        data: CommandParam<CommandType.swap>,
        playerType: PlayerType,
        isRender: boolean = true
    ): { x: number; y: number } | null {
        const unitParam = data.param;
        const unitType = unitParam.target.utype;
        const unitConfig = getUnitConfig(unitType);

        // 计算单位位置
        const position = this.getUnitPosition(unitParam);

        let unit = {
            /**单位id */
            id: unitParam.target?.id || 0,
            /**单位类型 */
            type: unitType,
            /**单位所属玩家 */
            player: data.player,
            /**血量 */
            hp: unitConfig.hp,
            /**攻击 */
            attack: unitConfig.attack,
            /**位置 */
            position: position,
        };

        if (!this.tiledMap) {
            this.tiledMap = this.getComponent(TiledMap);
        }

        if (!this.tiledMap) {
            LOG.error('MapRenderer: 未找到TiledMap组件');
            return null;
        }

        // 获取对象层
        let objectGroup = this.tiledMap.getObjectGroup('object');
        if (!objectGroup) {
            LOG.error('MapRenderer: 未找到对象层: object');
            return null;
        }

        // 创建TiledObject数据
        let config: TiledObjInitConfig = {
            id: unit.id,
            playerID: data.player,
            playerType: playerType,
            entityType: EntityType.unit,
            uType: unit.type,
            position: unit.position,
            name: `${getUnitConfig(unit.type).name}_${unit.id}`,
            clientTildeType: getClientTildeType(unit.type, EntityType.unit),
            healthBar: {
                current: unit.hp,
                max: unitConfig.hp,
                visible: true,
            },
        };

        // 优先从被删除的单位节点列表中获取节点进行重用
        let unitNode: Node;
        let isReusedNode = false;
        let childNode = objectGroup.node.getChildByName(`unit_${unit.id}`);
        if (childNode == undefined || childNode == null) {
           if (this.removeUnitNodes.length > 0) {
                // 从列表中取出一个节点进行重用
                unitNode = this.removeUnitNodes.pop()!;
                unitNode.name = `unit_${unit.id}`;
                isReusedNode = true;
            } else {
                // 列表为空时创建新节点
                unitNode = instantiate(this.tiledPrefab);
                unitNode.name = `unit_${unit.id}`;
                unitNode.active = false;
            }
            // 保存到映射表
            if (!this.unitNodes.has(unit.id)) {
                this.unitNodes.set(unit.id, unitNode);
            }
        }else{
            unitNode = this.unitNodes.get(unit.id);
            if(unitNode == undefined || unitNode == null){
                unitNode = objectGroup.node.getChildByName(`unit_${unit.id}`);
                this.unitNodes.set(unit.id,unitNode);
            }
        }

        let tiledObject = unitNode.getComponent(TiledObject);
        tiledObject.init(config);
        tiledObject.tipObj = this.tipinfo;

        // 如果是重用的节点，需要重新添加点击事件
        if (isReusedNode) {
            tiledObject.reAddClickEvent();
        }
        // 将节点添加到对象层
        objectGroup.node.addChild(unitNode);

        unitNode.active = true;
        if (isRender) {
            // 使用TiledObject的渲染方法创建节点内容
            tiledObject.createRenderNode(this.unitTileSize, playerType);
        }

        LOG.log(`MapRenderer: 创建单位: ID=${unit.id}, 类型=${unit.type}, 位置=(${unit.position.x}, ${unit.position.y})`);
        return unit.position;
    }

    /**
     * 更新单位位置
     * @param unit 单位数据
     * @param offsetPosition 位置偏移量
     * @returns 更新后的位置坐标
     */
    public updateUnitPosition(data: CommandParam<CommandType.move>, isRender: boolean = true): { x: number; y: number } | null {
        const moveParam = data.param;
        let unit = {
            /**单位id */
            id: moveParam.self.id,
            /**单位类型 */
            type: moveParam.self.utype,
            /**单位所属玩家 */
            player: data.player,
        };

        // 获取单位当前位置
        const unitData = this.unitNodes.get(unit.id);
        if (!unitData) {
            LOG.warn(`MapRenderer: 未找到单位节点: ${unit.id}`);
            return null;
        }

        let tiledObject = unitData.getComponent(TiledObject);
        let currentPosition = tiledObject.data.position;

        // 计算新位置（当前位置 + 偏移量）
        let position = {
            x: currentPosition.x + (moveParam.offsetPosition?.x || 0),
            y: currentPosition.y + (moveParam.offsetPosition?.y || 0),
        };

        // 逻辑 更新内部位置记录
        tiledObject.updatePosition(position);

        // 渲染 使用TiledObject的更新位置方法
        tiledObject.updateNodePosition(unitData, position, isRender);

        LOG.log(`MapRenderer: 更新单位位置: ID=${unit.id}, 新位置=(${position.x}, ${position.y})`);
        return position;
    }

    /**
     * 移除单位显示
     * @param unitId 单位ID
     */
    public removeUnit(unitId: number) {
        const unitData = this.unitNodes.get(unitId);
        if (!unitData) {
            LOG.warn(`MapRenderer: 未找到单位节点: ${unitId}`);
            return;
        }

        // 将节点移动到prefabs节点下并添加到删除列表
        if (unitData && unitData.isValid && unitData.parent && this.prefabs) {
            unitData.setParent(this.prefabs);
            unitData.setPosition(0, 0);
            unitData.active = false;
            this.removeUnitNodes.push(unitData);
            LOG.log(`MapRenderer: 移除单位: ID=${unitId}，已移动到prefabs节点`);
        } else {
            // 如果节点无效，直接销毁
            if (unitData && unitData.isValid) {
                unitData.destroy();
            }
        }
    }

    /**
     * 获取单位或建筑的TiledObject组件
     * @param entityId 实体ID
     * @param isBuilding 是否为建筑
     * @returns TiledObject组件或null
     */
    private getTiledObjectById(entityId: number, isBuilding: boolean = false): TiledObject | null {
        const entityData = isBuilding ? this.buildingNodes.get(entityId) : this.unitNodes.get(entityId);
        if (!entityData) {
            LOG.warn(`MapRenderer: 未找到${isBuilding ? '建筑' : '单位'}节点: ${entityId}`);
            return null;
        }
        return entityData.getComponent(TiledObject);
    }

    /**
     * 播放带方向的攻击动画
     * @param attackerTiledObject 攻击者TiledObject
     * @param targetTiledObject 目标TiledObject（可选）
     */
    private playDirectionalAttackAnimation(attackerTiledObject: TiledObject, targetTiledObject?: TiledObject): void {
        if (!attackerTiledObject) return;

        if (targetTiledObject && attackerTiledObject.animationManager) {
            const attackDirection = attackerTiledObject.animationManager.calculateAttackDirection(
                attackerTiledObject.data.position,
                targetTiledObject.data.position
            );
            // 如果是弓箭手，传递目标位置用于射箭动画
            if (attackerTiledObject.isArcher()) {
                attackerTiledObject.playAttackAnimation(attackDirection, targetTiledObject.data.position);
            }else if (attackerTiledObject.isTower()){
                attackerTiledObject.playAttackAnimation(attackDirection, targetTiledObject.data.position);
            } else {
                attackerTiledObject.playAttackAnimation(attackDirection);
            }
        } else {
            attackerTiledObject.playAttackAnimation();
        }
    }

    /**
     * 计算溅射目标位置
     * @param targetPosition 被攻击目标的位置
     * @param offsetPosition 攻击方向偏移量
     * @returns 溅射目标位置数组
     */
    private calculateSplashPositions(targetPosition: { x: number; y: number }, offsetPosition: { x: number; y: number }): { x: number; y: number }[] {
        // 根据攻击方向计算溅射目标位置
        // 如果攻击方向是(1,0)，则溅射位置是(1,1)和(1,-1)
        // 如果攻击方向是(0,1)，则溅射位置是(1,1)和(-1,1)
        // 如果攻击方向是(-1,0)，则溅射位置是(-1,1)和(-1,-1)
        // 如果攻击方向是(0,-1)，则溅射位置是(1,-1)和(-1,-1)
        const splashPositions: { x: number; y: number }[] = [];

        if (offsetPosition.x !== 0) {
            // 水平攻击，溅射到上下两个位置
            splashPositions.push(
                { x: targetPosition.x, y: targetPosition.y + 1 },
                { x: targetPosition.x, y: targetPosition.y - 1 }
            );
        } else if (offsetPosition.y !== 0) {
            // 垂直攻击，溅射到左右两个位置
            splashPositions.push(
                { x: targetPosition.x + 1, y: targetPosition.y },
                { x: targetPosition.x - 1, y: targetPosition.y }
            );
        }

        return splashPositions;
    }

    /**
     * 处理溅射伤害逻辑
     * @param attackerTiledObject 攻击者TiledObject
     * @param targetPosition 目标位置
     * @param offsetPosition 攻击方向偏移量
     * @param attackPower 攻击者攻击力
     * @returns 溅射伤害统计信息
     */
    private applySplashDamage(attackerTiledObject: TiledObject, targetPosition: { x: number; y: number }, offsetPosition: { x: number; y: number }, attackPower: number): { killedCount: number; damagedCount: number } {
        const splashDamage = Math.floor(attackPower * SplashDamageRatio);
        let killedCount = 0;
        let damagedCount = 0;

        // 计算溅射目标位置
        const splashPositions = this.calculateSplashPositions(targetPosition, offsetPosition);

        const deathUnitIds: number[] = [];

        // 对溅射位置的单位造成伤害
        for (const splashPos of splashPositions) {
            // 查找溅射位置的单位节点
            let splashUnitNode: Node | null = null;
            for (const [unitId, unitNode] of this.unitNodes) {
                try {
                    const unitTiledObject = unitNode.getComponent(TiledObject);
                    if (unitTiledObject &&
                        unitTiledObject.data.position.x === splashPos.x &&
                        unitTiledObject.data.position.y === splashPos.y) {
                        splashUnitNode = unitNode;
                        break;
                    }
                } catch (error) {
                    const unitTiledObject = unitNode.getComponent(TiledObject);
                    LOG.error(`MapRenderer: 处理溅射伤害时出错: ${error}`);
                }
            }
            
            if (splashUnitNode) {
                const splashTiledObject = splashUnitNode.getComponent(TiledObject);
                if (splashTiledObject && splashTiledObject.data.playerID != attackerTiledObject.data.playerID) {
                    // 对溅射目标造成伤害
                    const newSplashHP = splashTiledObject.data.healthBar.current - splashDamage;
                    splashTiledObject.updateHealth(newSplashHP);

                    // 如果溅射导致单位死亡
                    if (newSplashHP <= 0) {
                        const splashUnitId = splashTiledObject.data.id;
                        deathUnitIds.push(splashUnitId);
                        // 获取溅射击杀奖励
                        const splashUnitType = splashTiledObject.data.uType as UnitType;
                        const splashUnitConfig = getUnitConfig(splashUnitType);
                        const killedAward = splashUnitConfig.killedAward;

                        // 为攻击者播放击杀奖励动画
                        if (attackerTiledObject && attackerTiledObject.animationManager) {
                            attackerTiledObject.animationManager.playKilledAwardAnimation(killedAward);
                        }

                        LOG.log(`MapRenderer: 攻击单位: ID=${attackerTiledObject.data.id}, 溅射击杀单位: ID=${splashUnitId}, 获得奖励=${killedAward}`);
                        killedCount++;
                    } else {
                        LOG.log(`MapRenderer: 攻击单位: ID=${attackerTiledObject.data.id}, 溅射伤害单位: 位置=(${splashPos.x},${splashPos.y}), 伤害=${splashDamage}, 血量=${newSplashHP}`);
                        damagedCount++;
                    }
                }
            }
        }

        for (const deathUnitId of deathUnitIds) {
            this.removeUnit(deathUnitId);
        }

        return { killedCount, damagedCount };
    }

    /**
     * 处理攻击单位命令
     * @param data 攻击命令数据
     * @returns 返回击杀信息，包含是否击杀和击杀奖励
     */
    public attackUnit(data: CommandParam<CommandType.attack>, isRender: boolean = true): { isKilled: boolean; splashInfo?: { killedCount: number; damagedCount: number } } {
        const attackParam = data.param;

        // 获取攻击者和目标单位的TiledObject
        const attackerTiledObject = this.getTiledObjectById(attackParam.self.id, attackParam.self.type === EntityType.building);
        const targetTiledObject = this.getTiledObjectById(attackParam.target.id);

        // 播放带方向的攻击动画
        this.playDirectionalAttackAnimation(attackerTiledObject, targetTiledObject);

        // 获取目标单位ID
        const targetUnitId = attackParam.target.id;

        // 查找目标单位
        const unitData = this.unitNodes.get(targetUnitId);
        if (!unitData) {
            LOG.warn(`MapRenderer: 未找到目标单位节点: ${targetUnitId}`);
            return;
        }

        const tiledObject = unitData.getComponent(TiledObject);

        // 根据攻击者类型获取攻击力
        let attackPower = 0;
        if (attackParam.self.type === EntityType.unit) {
            let unitType = attackParam.self.utype as UnitType;
            let unitConfig = getUnitConfig(unitType);
            attackPower = unitConfig.attack;
        } else if (attackParam.self.type === EntityType.building) {
            let buildingType = attackParam.self.utype as BuildingType;
            let buildingConfig = getBuildingConfig(buildingType);
            attackPower = buildingConfig.attack;
        }

        let newTargetHP = tiledObject.data.healthBar.current - attackPower;
        tiledObject.updateHealth(newTargetHP);

        // 如果单位血量为0，则移除单位
        if (newTargetHP <= 0) {
            this.removeUnit(targetUnitId);
            // 从配置中获取击杀奖励
            const targetUnitType = attackParam.target.utype as UnitType;
            const targetUnitConfig = getUnitConfig(targetUnitType);
            const killedAward = targetUnitConfig.killedAward;
            // 为攻击者播放击杀奖励动画
            if (attackerTiledObject && attackerTiledObject.animationManager) {
                attackerTiledObject.animationManager.playKilledAwardAnimation(killedAward);
            }
            LOG.log(`MapRenderer: 单位被击杀: ID=${targetUnitId}, 获得奖励=${killedAward}`);
            
            // 士兵攻击单位时的溅射伤害（仅对敌方单位有效）
            let splashInfo: { killedCount: number; damagedCount: number } | undefined;
            if (attackParam.self.type === EntityType.unit) {
                const attackerUnitType = attackParam.self.utype as UnitType;
                if (attackerUnitType === UnitType.soldier) {
                    // 获取目标单位位置
                    const targetPosition = {
                        x: tiledObject.data.position.x,
                        y: tiledObject.data.position.y
                    };

                    // 处理溅射伤害
                    splashInfo = this.applySplashDamage(
                        attackerTiledObject,
                        targetPosition,
                        attackParam.offsetPosition,
                        attackPower
                    );
                }
            }
            
            return { isKilled: true, splashInfo };
        }

        LOG.log(`MapRenderer: 单位受到攻击: ID=${targetUnitId}, 血量=${newTargetHP}`);

        // 士兵攻击单位时的溅射伤害（仅对敌方单位有效）
        let splashInfo: { killedCount: number; damagedCount: number } | undefined;
        if (attackParam.self.type === EntityType.unit) {
            const attackerUnitType = attackParam.self.utype as UnitType;
            if (attackerUnitType === UnitType.soldier) {
                // 获取目标单位位置
                const targetPosition = {
                    x: tiledObject.data.position.x,
                    y: tiledObject.data.position.y
                };

                // 处理溅射伤害
                splashInfo = this.applySplashDamage(
                    attackerTiledObject,
                    targetPosition,
                    attackParam.offsetPosition,
                    attackPower
                );
            }
        }

        return { isKilled: false, splashInfo };
    }

    /**
     * 治疗单位
     * @param data 治疗命令数据
     */
    public healUnit(data: CommandParam<CommandType.heal>, isRender: boolean = true) {
        const healParam = data.param;
        const healerId = healParam.self.id;
        const targetUnitId = healParam.target.id;

        if (!targetUnitId) {
            LOG.error('MapRenderer: healUnit: 目标单位ID为空');
            return;
        }

        // 获取治疗者和目标单位的TiledObject
        const healerTiledObject = this.getTiledObjectById(healerId);
        const targetTiledObject = this.getTiledObjectById(targetUnitId);

        // 播放带方向的攻击动画
        this.playDirectionalAttackAnimation(healerTiledObject, targetTiledObject);

        const unitData = this.unitNodes.get(targetUnitId);
        if (!unitData) {
            LOG.warn(`MapRenderer: 未找到目标单位节点: ${targetUnitId}`);
            return;
        }

        const tiledObject = unitData.getComponent(TiledObject);
        if (!tiledObject) {
            LOG.error(`MapRenderer: 单位节点缺少TiledObject组件: ${targetUnitId}`);
            return;
        }

        // 获取治疗者的治疗量
        let healerType = healParam.self?.utype as UnitType;
        let healerConfig = getUnitConfig(healerType);
        let healAmount = healerConfig.attack; // 治疗兵的attack值就是治疗量

        // 计算治疗后的血量，不能超过最大血量
        let newTargetHP = Math.min(tiledObject.data.healthBar.current + healAmount, tiledObject.data.healthBar.max);
        tiledObject.updateHealth(newTargetHP);

        LOG.log(
            `MapRenderer: 单位受到治疗: ID=${targetUnitId}, 治疗量=${healAmount}, 血量=${tiledObject.data.healthBar.current}=>${newTargetHP}`
        );
    }

    /**
     * 处理资源采集命令
     * @param data 采集命令数据
     * @param isRender 是否渲染动画效果
     */
    public collectResource(data: CommandParam<CommandType.collect>, isRender: boolean = true) {
        const collectParam = data.param;
        const collectorId = collectParam.self.id;
        const resourceType = collectParam.target?.utype as TildeType;

        if (!collectorId) {
            LOG.error('MapRenderer: collectResource: 采集者ID为空');
            return;
        }

        // 获取采集者单位节点
        const unitData = this.unitNodes.get(collectorId);
        if (!unitData) {
            LOG.warn(`MapRenderer: 未找到采集者单位节点: ${collectorId}`);
            return;
        }

        // 计算目标位置
        const tiledObject = unitData.getComponent(TiledObject);
        if (!tiledObject) {
            LOG.error(`MapRenderer: 单位节点缺少TiledObject组件: ${collectorId}`);
            return;
        }

        const collectorPosition = tiledObject.data.position;
        const targetPosition = {
            x: collectorPosition.x + (collectParam.offsetPosition?.x || 0),
            y: collectorPosition.y + (collectParam.offsetPosition?.y || 0),
        };

        // 获取资源价值
        const resourceValue = ResourceConfig[resourceType].value;

        // 播放带方向的攻击动画
        const collectorTiledObject = this.getTiledObjectById(collectorId);
        if (collectorTiledObject && collectorTiledObject.animationManager) {
            const collectDirection = collectorTiledObject.animationManager.calculateAttackDirection(
                collectorPosition,
                targetPosition
            );
            collectorTiledObject.playAttackAnimation(collectDirection);
            tiledObject.playCollectAnimation(resourceValue);
        }

        // 在这里可以添加采集动画效果
        if (isRender) {
            // 可以添加粒子效果或动画
            // 例如：闪光效果、资源飞向采集者的动画等
            LOG.log(
                `MapRenderer: 显示采集动画效果: 采集者ID=${collectorId}, 资源类型=${ResourceConfig[resourceType].name}, 位置=(${targetPosition.x}, ${targetPosition.y})`
            );
        }

        LOG.log(
            `MapRenderer: 资源采集: 采集者ID=${collectorId}, 资源类型=${ResourceConfig[resourceType].name}, 价值=${resourceValue}, 位置=(${targetPosition.x}, ${targetPosition.y})`
        );
    }

    /**
     * 清空所有单位
     */
    public clearAllUnits(): void {
        // 遍历所有单位节点，逐个清理
        for (const [unitId, unitData] of this.unitNodes) {
            // 将节点移动到prefabs节点下而不是销毁
            if (unitData && unitData.parent && this.prefabs) {
                unitData.setParent(this.prefabs);
                unitData.setPosition(0, 0);
                unitData.active = false;
                // 将节点添加到被删除单位列表中
                this.removeUnitNodes.push(unitData);
            }
        }

        // 清空单位节点映射表
        this.unitNodes.clear();
    }

    // ==================== 建筑渲染方法 ====================

    /**
     * 创建建筑显示节点
     * @param building 建筑数据
     * @param playerType 玩家类型
     */
    public createBuilding(
        data: CommandParam<CommandType.build>,
        playerType: PlayerType,
        isRender: boolean = true
    ): { x: number; y: number } | null {
        let buildParam = data.param;
        let buildingType = buildParam.target.utype;
        let buildingConfig = getBuildingConfig(buildingType);

        // 计算建筑位置
        const position = this.getBuildingPosition(buildParam);

        // 获取建造者单位播放攻击动画（如果不是建造兵）
        if (buildParam.target.utype !== BuildingType.base) {
            const builderId = buildParam.self.id;
            const builderTiledObject = this.getTiledObjectById(builderId);
            if (builderTiledObject && builderTiledObject.animationManager) {
                // 计算建造方向并播放攻击动画
                const buildDirection = builderTiledObject.animationManager.calculateAttackDirection(
                    builderTiledObject.data.position,
                    position
                );
                builderTiledObject.playAttackAnimation(buildDirection);
            }
        }

        let building = {
            /**建筑id */
            id: buildParam.target.id,
            /**建筑类型 */
            type: buildingType,
            /**建筑所属玩家 */
            player: data.player,
            /**建筑血量 */
            hp: buildingConfig.hp,
            /**位置 */
            position: position,
        };

        // 检查建筑是否已存在
        if (this.buildingNodes.has(building.id)) {
            LOG.warn(`MapRenderer: 建筑 ${building.id} 已存在，无法重复创建`);
            return null;
        }

        if (!this.tiledMap) {
            this.tiledMap = this.getComponent(TiledMap);
        }

        if (!this.tiledMap) {
            LOG.error('MapRenderer: 未找到TiledMap组件');
            return null;
        }

        // 获取对象层
        let objectGroup = this.tiledMap.getObjectGroup('object');
        if (!objectGroup) {
            LOG.error('MapRenderer: 未找到对象层: object');
            return null;
        }

        // 创建TiledObject数据
        let config: TiledObjInitConfig = {
            id: building.id,
            playerID: data.player,
            playerType: playerType,
            entityType: EntityType.building,
            uType: building.type,
            position: building.position,
            name: `${getBuildingConfig(building.type).name}_${building.id}`,
            clientTildeType: getClientTildeType(building.type, EntityType.building),
            healthBar: {
                current: building.hp,
                max: buildingConfig.hp,
                visible: true,
            },
        };

        // 优先从被删除的建筑节点列表中获取节点进行重用
        let buildingNode: Node;
        let isReusedNode = false;
        if (this.removeBuildingNodes.length > 0) {
            // 从列表中取出一个节点进行重用
            buildingNode = this.removeBuildingNodes.pop()!;
            buildingNode.name = `${building.id}`;
            // 从prefabs节点下移除
            if (buildingNode.parent === this.prefabs) {
                this.prefabs.removeChild(buildingNode);
            }
            isReusedNode = true;
            LOG.log(`MapRenderer: 重用建筑节点: ID=${building.id}`);
        } else {
            // 列表为空时创建新节点
            buildingNode = instantiate(this.tiledPrefab);
            buildingNode.name = `${building.id}`;
            buildingNode.active = false;
            LOG.log(`MapRenderer: 创建新建筑节点: ID=${building.id}`);
        }
        let tiledObject = buildingNode.getComponent(TiledObject);
        tiledObject.init(config);
        tiledObject.tipObj = this.tipinfo;

        // 如果是重用的节点，需要重新添加点击事件
        if (isReusedNode) {
            tiledObject.reAddClickEvent();
        }

        if (building.type === BuildingType.base) {
            //根据建筑攻击范围改变地形
            this.changeTerrainByAttackRange(building.position, buildingConfig.attackRange);
        }

        // 将节点添加到对象层
        objectGroup.node.addChild(buildingNode);
        buildingNode.active = true;
        if (isRender) {
            // 使用TiledObject的渲染方法创建节点内容
            tiledObject.createRenderNode(this.buildingTileSize, playerType);
        }

        // 保存到映射表
        this.buildingNodes.set(building.id, buildingNode);

        LOG.log(
            `MapRenderer: 创建建筑: ID=${building.id}, 类型=${building.type}, 位置=(${building.position.x}, ${building.position.y})`
        );
        return building.position;
    }

    /**
     * 移除建筑显示
     * @param buildingId 建筑ID
     */
    public removeBuilding(buildingId: number) {
        const buildingData = this.buildingNodes.get(buildingId);
        if (!buildingData) {
            LOG.warn(`MapRenderer: 未找到建筑节点: ${buildingId}`);
            return;
        }

        const tiledObject = buildingData.getComponent(TiledObject);
        if (!tiledObject) {
            LOG.error(`MapRenderer: 建筑节点缺少TiledObject组件: ${buildingId}`);
            return;
        }

        // 播放死亡动画
        tiledObject.playDeathAnimation();

        // 延迟移除建筑，等待死亡动画播放完成
        setTimeout(() => {
            // 检查节点是否仍然有效
            if (buildingData && buildingData.isValid && buildingData.parent && this.prefabs) {
                buildingData.setParent(this.prefabs);
                buildingData.setPosition(0, 0);
                buildingData.active = false;
                // 将节点添加到被删除建筑列表中
                this.removeBuildingNodes.push(buildingData);
            }else{
                if(buildingData){
                    buildingData.destroy();
                }
            }

            // 从映射表中移除
            this.buildingNodes.delete(buildingId);
        }, 1000); // 等待1秒让死亡动画播放完成
    }

    /**
     * 处理攻击建筑命令
     * @param data 攻击命令数据
     * @returns 返回击杀信息，包含是否击杀和击杀奖励
     */
    public attackBuilding(data: CommandParam<CommandType.attack>, isRender: boolean = true): boolean {
        const attackParam = data.param;

        // 获取攻击者和目标建筑的TiledObject
        const attackerTiledObject = this.getTiledObjectById(attackParam.self.id, attackParam.self.type === EntityType.building);
        const targetBuildingTiledObject = this.getTiledObjectById(attackParam.target.id, true);

        // 播放带方向的攻击动画
        this.playDirectionalAttackAnimation(attackerTiledObject, targetBuildingTiledObject);

        // 获取目标建筑ID
        const targetBuildingId = attackParam.target.id;

        // 查找目标建筑
        const buildingData = this.buildingNodes.get(targetBuildingId);
        if (!buildingData) {
            LOG.warn(`MapRenderer: 未找到目标建筑节点: ${targetBuildingId}`);
            return;
        }

        const tiledObject = buildingData.getComponent(TiledObject);

        // 根据攻击者类型获取攻击力
        let attackPower = 0;
        if (attackParam.self.type === EntityType.unit) {
            let unitType = attackParam.self?.utype as UnitType;
            let unitConfig = getUnitConfig(unitType);
            attackPower = unitConfig.attack;
        } else if (attackParam.self.type === EntityType.building) {
            let buildingType = attackParam.self?.utype as BuildingType;
            let buildingConfig = getBuildingConfig(buildingType);
            attackPower = buildingConfig.attack;
        }

        let newTargetHP = tiledObject.data.healthBar.current - attackPower
        tiledObject.updateHealth(newTargetHP);

        // 如果建筑血量为0，则移除建筑（基地除外）
        if (newTargetHP <= 0) {
            const targetBuildingType = attackParam.target.utype as BuildingType;
            // 从配置中获取击杀奖励
            const targetBuildingConfig = getBuildingConfig(targetBuildingType);
            const killedAward = targetBuildingConfig.killedAward;
            // 为攻击者播放击杀奖励动画
            if (attackerTiledObject && attackerTiledObject.animationManager) {
                attackerTiledObject.animationManager.playKilledAwardAnimation(killedAward);
            }
            // 如果不是基地，则移除建筑
            if (targetBuildingType !== BuildingType.base) {
                this.removeBuilding(targetBuildingId);
            }
            LOG.log(`MapRenderer: 建筑被摧毁: ID=${targetBuildingId}, 类型=${targetBuildingType === BuildingType.base ? '基地' : '普通建筑'}, 获得奖励=${killedAward}`);
            return true;
        }

        LOG.log(`MapRenderer: 建筑受到攻击: ID=${targetBuildingId}, 血量=${newTargetHP}`);
        return false;
    }

    /**
     * 清空所有建筑
     */
    public clearAllBuildings(): void {
        // 遍历所有建筑节点，逐个清理
        for (const [buildingId, buildingData] of this.buildingNodes) {
            // 将节点移动到prefabs节点下而不是销毁
            if (buildingData && buildingData.parent && this.prefabs) {
                buildingData.setParent(this.prefabs);
                buildingData.setPosition(0, 0);
                buildingData.active = false;
                // 将节点添加到被删除建筑列表中
                this.removeBuildingNodes.push(buildingData);
            }
        }
        // 清空建筑节点映射表
        this.buildingNodes.clear();
    }

    /**
     * 清空所有地形节点
     */
    public clearAllTerrain(): void {
        // 遍历所有地形节点，逐个清理
        for (const [terrainId, terrainData] of this.terrainNodes) {
            // 将节点移动到prefabs节点下而不是销毁
            if (terrainData && terrainData.parent && this.prefabs) {
                terrainData.setParent(this.prefabs);
                terrainData.setPosition(0, 0);
                terrainData.active = false;
                // 将节点添加到被删除地形列表中
                this.removeTerrainNodes.push(terrainData);
            }else{
                if(terrainData){
                    terrainData.destroy();
                }
            }
        }

        // 清空地形节点映射表
        this.terrainNodes.clear();

        LOG.log('MapRenderer: 已清空所有地形节点，已移动到prefabs节点');
    }

    // ==================== 通用方法 ====================

    /**
     * 遍历并渲染所有节点
     * 如果节点的isRender为false，先创建渲染节点，然后更新位置
     */
    public renderAllNodes() {
        try {
            // 遍历所有单位节点
            for (const [unitId, unitNode] of this.unitNodes) {
                // 检查节点是否有效
                if (!unitNode || !unitNode.isValid) {
                    LOG.warn(`MapRenderer: 单位节点无效，ID=${unitId}，跳过渲染`);
                    continue;
                }

                try {
                    const tiledObject = unitNode.getComponent(TiledObject);
                    if (tiledObject && !tiledObject.data.isRender) {
                        // 如果未渲染，先创建渲染节点
                        tiledObject.createRenderNode(this.unitTileSize, tiledObject.data.playerType);
                    }
                    // 先停止所有动画和tween，确保位置更新不会被干扰
                    if (tiledObject) {
                        // 更新节点位置（不使用动画）
                        tiledObject.updateNodePosition(unitNode, tiledObject.data.position, false);
                    }
                } catch (error) {
                    LOG.error(`MapRenderer: 渲染单位节点时出错，ID=${unitId}`, error);
                }
            }

            // 遍历所有建筑节点
            for (const [buildingId, buildingNode] of this.buildingNodes) {
                // 检查节点是否有效
                if (!buildingNode || !buildingNode.isValid) {
                    LOG.warn(`MapRenderer: 建筑节点无效，ID=${buildingId}，跳过渲染`);
                    continue;
                }

                try {
                    const tiledObject = buildingNode.getComponent(TiledObject);
                    if (tiledObject && !tiledObject.data.isRender) {
                        // 如果未渲染，先创建渲染节点
                        tiledObject.createRenderNode(this.buildingTileSize, tiledObject.data.playerType);
                    }
                    // 先停止所有动画和tween，确保位置更新不会被干扰
                    if (tiledObject) {
                        // 更新节点位置（不使用动画）
                        tiledObject.updateNodePosition(buildingNode, tiledObject.data.position, false);
                    }
                } catch (error) {
                    LOG.error(`MapRenderer: 渲染建筑节点时出错，ID=${buildingId}`, error);
                }
            }

            LOG.log('MapRenderer: 已完成所有节点的渲染和位置更新');
        } catch (error) {
            LOG.error('MapRenderer: renderAllNodes 执行过程中发生错误:', error);
        }
    }

    /**
     * 清空所有渲染对象（单位、建筑和地形）
     */
    public clearAllRenderObjects(): void {
        this.clearAllUnits();
        this.clearAllBuildings();
        this.clearAllTerrain();
        // 重播时彻底销毁所有已移除的节点
        this.destroyAllRemovedNodes();
        LOG.log('MapRenderer: 已清空所有渲染对象');
    }

    /**
     * 设置所有单位ID标签的可见性
     * @param visible 是否可见
     */
    public setAllUnitsIdVisible(visible: boolean): void {
        for (const [unitId, unitNode] of this.unitNodes) {
            if (unitNode && unitNode.isValid) {
                const tiledObject = unitNode.getComponent(TiledObject);
                if (tiledObject) {
                    tiledObject.setIdLabelVisible(visible);
                }
            }
        }
        LOG.log(`MapRenderer: 已设置所有单位ID标签可见性为 ${visible}`);
    }

    /**
     * 设置所有建筑ID标签的可见性
     * @param visible 是否可见
     */
    public setAllBuildingsIdVisible(visible: boolean): void {
        for (const [buildingId, buildingNode] of this.buildingNodes) {
            if (buildingNode && buildingNode.isValid) {
                const tiledObject = buildingNode.getComponent(TiledObject);
                if (tiledObject) {
                    tiledObject.setIdLabelVisible(visible);
                }
            }
        }
        LOG.log(`MapRenderer: 已设置所有建筑ID标签可见性为 ${visible}`);
    }

    /**
     * 设置所有对象ID标签的可见性
     * @param visible 是否可见
     */
    public setAllIdLabelsVisible(visible: boolean): void {
        this.setAllUnitsIdVisible(visible);
        this.setAllBuildingsIdVisible(visible);
        LOG.log(`MapRenderer: 已设置所有ID标签可见性为 ${visible}`);
    }

    /**
     * 获取指定ID的单位节点
     * @param unitId 单位ID
     * @returns 单位节点，如果不存在则返回null
     */
    public getUnitNode(unitId: number): Node | null {
        return this.unitNodes.get(unitId) || null;
    }

    /**
     * 获取指定ID的建筑节点
     * @param buildingId 建筑ID
     * @returns 建筑节点，如果不存在则返回null
     */
    public getBuildingNode(buildingId: number): Node | null {
        return this.buildingNodes.get(buildingId) || null;
    }

    /**
     * 计算并返回建筑的建造位置
     * @param buildParam 建造命令参数
     * @returns 建筑的建造位置，如果无法计算则返回{x:0,y:0}
     */
    public getBuildingPosition(buildParam: BuildCommandParam): { x: number; y: number } {
        let position = buildParam.offsetPosition;

        // 如果是建造命令，需要计算建筑的实际位置
        if (buildParam.self && buildParam.offsetPosition) {
            // 获取建造者单位的位置
            const builderId = buildParam.self.id;
            const builderNode = this.unitNodes.get(builderId);
            if (builderNode) {
                const builderTiledObject = builderNode.getComponent(TiledObject);
                if (builderTiledObject) {
                    const builderPosition = builderTiledObject.data.position;
                    // 计算建筑的实际位置（建造者位置 + 偏移量）
                    position = {
                        x: builderPosition.x + (buildParam.offsetPosition.x || 0),
                        y: builderPosition.y + (buildParam.offsetPosition.y || 0),
                    };
                }
            }
        }

        return position;
    }

    /**
     * 计算并返回单位的生产位置
     * @param unitParam 生产单位命令参数
     * @returns 单位的生产位置，如果无法计算则返回{x:0,y:0}
     */
    public getUnitPosition(unitParam: SwapCommandParam): { x: number; y: number } {
        let position = unitParam.offsetPosition;

        // 如果是生产单位命令，需要计算单位的实际位置
        if (unitParam.self && unitParam.offsetPosition) {
            // 获取生产建筑的位置
            const buildingId = unitParam.self.id;
            const buildingNode = this.buildingNodes.get(buildingId);
            if (buildingNode) {
                const buildingTiledObject = buildingNode.getComponent(TiledObject);
                if (buildingTiledObject) {
                    const buildingPosition = buildingTiledObject.data.position;
                    // 计算单位的实际位置（建筑位置 + 偏移量）
                    position = {
                        x: buildingPosition.x + (unitParam.offsetPosition.x || 0),
                        y: buildingPosition.y + (unitParam.offsetPosition.y || 0),
                    };
                }
            }
        }

        return position;
    }


    // ==================== 被删除节点管理方法 ====================

    /**
     * 获取被删除的单位节点列表
     * @returns 被删除的单位节点数组
     */
    public getRemovedUnitNodes(): Node[] {
        return this.removeUnitNodes;
    }

    /**
     * 获取被删除的建筑节点列表
     * @returns 被删除的建筑节点数组
     */
    public getRemovedBuildingNodes(): Node[] {
        return this.removeBuildingNodes;
    }

    /**
     * 获取被删除的地形节点列表
     * @returns 被删除的地形节点数组
     */
    public getRemovedTerrainNodes(): Node[] {
        return this.removeTerrainNodes;
    }

    /**
     * 清空被删除的单位节点列表
     */
    public clearRemovedUnitNodes(): void {
        // 销毁所有被删除的单位节点
        for (const node of this.removeUnitNodes) {
            if (node && node.isValid) {
                node.destroy();
            }
        }
        this.removeUnitNodes = [];
        LOG.log('MapRenderer: 已清空被删除的单位节点列表');
    }

    /**
     * 清空被删除的建筑节点列表
     */
    public clearRemovedBuildingNodes(): void {
        // 销毁所有被删除的建筑节点
        for (const node of this.removeBuildingNodes) {
            if (node && node.isValid) {
                node.destroy();
            }
        }
        this.removeBuildingNodes = [];
        LOG.log('MapRenderer: 已清空被删除的建筑节点列表');
    }

    /**
     * 清空被删除的地形节点列表
     */
    public clearRemovedTerrainNodes(): void {
        // 销毁所有被删除的地形节点
        for (const node of this.removeTerrainNodes) {
            if (node && node.isValid) {
                node.destroy();
            }
        }
        this.removeTerrainNodes = [];
        LOG.log('MapRenderer: 已清空被删除的地形节点列表');
    }

    /**
     * 清空所有被删除的节点列表
     */
    public clearAllRemovedNodes(): void {
        this.clearRemovedUnitNodes();
        this.clearRemovedBuildingNodes();
        this.clearRemovedTerrainNodes();
        LOG.log('MapRenderer: 已清空所有被删除的节点列表');
    }

    /**
     * 彻底销毁所有节点（重播时使用）
     */
    public destroyAllRemovedNodes(): void {
        LOG.log('MapRenderer: 开始彻底销毁所有节点');

        // 销毁所有单位节点
        this.unitNodes.forEach((node, unitId) => {
            if (node && node.isValid) {
                node.destroy();
            }
        });
        this.unitNodes.clear();

        // 销毁所有建筑节点
        this.buildingNodes.forEach((node, buildingId) => {
            if (node && node.isValid) {
                node.destroy();
            }
        });
        this.buildingNodes.clear();

        // 销毁所有地形节点
        this.terrainNodes.forEach((node, key) => {
            if (node && node.isValid) {
                node.destroy();
            }
        });
        this.terrainNodes.clear();

        // 清空已移除的节点列表
        this.clearAllRemovedNodes();

        LOG.log('MapRenderer: 所有节点已彻底销毁');
    }

    /**
     * 根据建筑攻击范围改变周围地形
     * @param centerPosition 建筑中心位置
     * @param attackRange 攻击范围
     */
    public changeTerrainByAttackRange(centerPosition: { x: number, y: number }, attackRange: number): void {
        if (!this.mapData) {
            LOG.error('MapRenderer: 地图数据为空，无法改变地形');
            return;
        }

        const height = this.mapData.length;
        const width = this.mapData[0].length;
        LOG.log(`MapRenderer: 开始根据基地攻击范围改变地形，中心位置: (${centerPosition.x}, ${centerPosition.y})，攻击范围: ${attackRange}`);

        // 获取对象层
        let plainLayer = this.tiledMap.getLayer('plain');

        if (!plainLayer) {
            LOG.error('MapRenderer: 未找到地图层: plain');
            return;
        }

        let changedCount = 0;

        // 遍历攻击范围内的所有位置
        for (let y = Math.max(0, centerPosition.y - attackRange); y <= Math.min(height - 1, centerPosition.y + attackRange); y++) {
            for (let x = Math.max(0, centerPosition.x - attackRange); x <= Math.min(width - 1, centerPosition.x + attackRange); x++) {
                //LOG.log(`改变 ${x},${y} 位置地形块`);
                let tiledtile = plainLayer.getTiledTileAt(x,y);
                if(tiledtile == undefined){
                    tiledtile = plainLayer.getTiledTileAt(x,y,true);
                    tiledtile.grid = 2;
                }
            }
        }

        LOG.log(`MapRenderer: 基地攻击范围地形改变完成，共改变了 ${changedCount} 个地形块`);
    }

    protected onDestroy(): void {
        this.clearMessage();
    }
}
